package de.tu_darmstadt.gdi1.xcom.tests.testcases.students;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

import de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1;

/**
 * 
 * Test if the current level is solved
 * 
 * @author Lukas Schwoebel
 *
 */
public class LevelWonTest {
	
	private XcomTestAdapterLevel1 testAdapter;
	
	private String testLevel2_level = "" +
				"#######\n" +
				"#....##\n" +
				"##..###\n" +
				"#######";
	
	private String testLevel2_mob1 = "\n" +
				"//{mobs}\n" +
				"//@;1;1;n;50;75;50;50;10\n" +
				"//Z;2;1;n;50;75;50;50;10";
	
	private String testLevel2_mob2 = "\n" +
				"//{mobs}\n" +
				"//Z;2;1;n;50;75;50;50;10";
	
	private String testLevel2_mob3 = "\n" +
				"//{mobs}\n" +
				"//@;1;1;n;50;75;50;50;10";
				
	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		testAdapter = new XcomTestAdapterLevel1();
	}

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#isWon()}.
	 */
	@Test
	public final void testIsWonAfterLoading() {

		// test if directly after loading without any interaction a level is recognised as lost or won
		// also, correctness-test (just for one testcase needed)
		
		// standard-testlevel, not won or lost
		testAdapter.loadLevelFromString(TestLevel.testLevel);
		assertFalse("Level is not won: "+testAdapter.levelRepresentationAsString(), testAdapter.isWon());
		assertFalse("Level is not lost: "+testAdapter.levelRepresentationAsString(), testAdapter.isLost());
		assertTrue("Level is correct: "+testAdapter.levelRepresentationAsString(), testAdapter.isCorrectLevel(TestLevel.testLevel));
		
		// "normal" level, not won or lost
		testAdapter.loadLevelFromString(testLevel2_level + testLevel2_mob1);
		assertFalse("Level is not won: "+testAdapter.levelRepresentationAsString(), testAdapter.isWon());
		assertFalse("Level is not lost: "+testAdapter.levelRepresentationAsString(), testAdapter.isLost());
		assertTrue("Level is correct: "+testAdapter.levelRepresentationAsString(), testAdapter.isCorrectLevel(testLevel2_level + testLevel2_mob1));
		
		// level without humans, lost
		// NOTE: this level should be considered as "not correct" as there are no humans, but the loading of the level
		// should be done anyways as its representation is correct, but it should be lost at the beginning
		testAdapter.loadLevelFromString(testLevel2_level + testLevel2_mob2);
		assertFalse("Level is not won: "+testAdapter.levelRepresentationAsString(), testAdapter.isWon());
		assertTrue("Level is lost: "+testAdapter.levelRepresentationAsString(), testAdapter.isLost());
		assertFalse("Level is not correct: "+testAdapter.levelRepresentationAsString(), testAdapter.isCorrectLevel(testLevel2_level + testLevel2_mob2));

		// level without zombies, won
		testAdapter.loadLevelFromString(testLevel2_level + testLevel2_mob3);
		assertTrue("Level is won: "+testAdapter.levelRepresentationAsString(), testAdapter.isWon());
		assertFalse("Level is not lost: "+testAdapter.levelRepresentationAsString(), testAdapter.isLost());
		assertTrue("Level is correct: "+testAdapter.levelRepresentationAsString(), testAdapter.isCorrectLevel(testLevel2_level + testLevel2_mob3));
	}
	

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#isWon()}.
	 */
	@Test
	public final void testIsWonAfterPlaying() {

		// performing some interaction and killing all zombies in the first pass, level should be won after that
		
		// standard-testlevel, not won or lost
		testAdapter.loadLevelFromString(TestLevel.testLevel);
		assertFalse("Level is not won: "+testAdapter.levelRepresentationAsString(),  testAdapter.isWon());
		assertFalse("Level is not lost: "+testAdapter.levelRepresentationAsString(), testAdapter.isLost());
		assertTrue("Level is correct: "+testAdapter.levelRepresentationAsString(), testAdapter.isCorrectLevel(TestLevel.testLevel));
		
		// turn around and kill first alien with first player
		testAdapter.rotateActivePlayer(false);
		testAdapter.performActionForActivePlayer();
		
		// kill second alien with first player
		testAdapter.performActionForActivePlayer();
		testAdapter.performActionForActivePlayer();
		
		// little test, just "to be sure"
		assertFalse("There are still enemies in the game, it is not won yet: "+testAdapter.levelRepresentationAsString(), testAdapter.isWon());
		assertFalse("There are still humans in the game, it is not lost yet: "+testAdapter.levelRepresentationAsString(), testAdapter.isLost());
		
		// now kill the other aliens
		// open door with second human, this should only be necessary for higher
		// level implementations, in the first level this should result in
		// the try to walk into a wall
		testAdapter.changeActivePlayer(2, 5);
		testAdapter.rotateActivePlayer(false);
		testAdapter.performActionForActivePlayer();
		testAdapter.rotateActivePlayer(true);
		testAdapter.performActionForActivePlayer();
		// walk with third human to kill
		testAdapter.changeActivePlayer(4, 6);
		testAdapter.rotateActivePlayer(true);
		testAdapter.performActionForActivePlayer();
		testAdapter.performActionForActivePlayer();
		testAdapter.performActionForActivePlayer();
		testAdapter.rotateActivePlayer(false);
		testAdapter.performActionForActivePlayer();
		testAdapter.rotateActivePlayer(true);
		testAdapter.performActionForActivePlayer();
		testAdapter.performActionForActivePlayer();
		testAdapter.rotateActivePlayer(false);
		testAdapter.performActionForActivePlayer();
		testAdapter.performActionForActivePlayer();
		testAdapter.performActionForActivePlayer();
		testAdapter.rotateActivePlayer(false);

		// little test, just "to be sure", last alien to be killed
		assertFalse("There are still enemies in the game, it is not won yet: "+testAdapter.levelRepresentationAsString(), testAdapter.isWon());
		assertFalse("There are still humans in the game, it is not lost yet: "+testAdapter.levelRepresentationAsString(), testAdapter.isLost());
		
		
		testAdapter.performActionForActivePlayer();
		
		// now every alien was killed, game should be won
		assertTrue("There are no enemies left in the game, it should be won: "+testAdapter.levelRepresentationAsString(), testAdapter.isWon());
		assertFalse("The game is won and there are still humans left, it should not be lost: "+testAdapter.levelRepresentationAsString(), testAdapter.isLost());
	}


	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#isLost()}.
	 */
	@Test
	public final void testIsLostAfterThreeRounds() {
	
		testAdapter.loadLevelFromString(TestLevel.testLevel);
		
		assertFalse("Level is not lost after loading:\n"+testAdapter.levelRepresentationAsString(), testAdapter.isLost());
		
		// end turn until "lost"
		for(int i = 0; i < TestLevel.lostAfterRound; i++) {
			assertFalse("Level is not lost in the "+(i+1)+". turn:\n"+testAdapter.levelRepresentationAsString(), testAdapter.isLost());
			testAdapter.endTurn();
		}
		assertTrue("After "+TestLevel.lostAfterRound+" turns the level should be lost", testAdapter.isLost());
		
		// now check if it is really lost, so the level is "locked" and no further actions are possible
		
		testAdapter.changeActivePlayer(4, 2);
		testAdapter.rotateActivePlayer(true);
		assertEquals("Level is lost, no action should be possible, so player at 4:2 should still face " +
				"north after a rotation", 1, testAdapter.activePlayerLookingToDirection());
		
		String levelBeforeAction = testAdapter.levelRepresentationAsString();
		testAdapter.performActionForActivePlayer();
		assertEquals("Level is lost, no action should be possible, so player should still be at 4:2 after 'movement'-action",
				levelBeforeAction, testAdapter.levelRepresentationAsString());
		
	}
}
